#include "MessageItem.h"
#include <QLabel>
#include <QPushButton>
#include <QGridLayout>
#include <QFont>
MessageItem::MessageItem(bool isLeft, std::shared_ptr<Message> message)
    : m_isLeft(isLeft)
{
    // 初始化UI
    initUI(std::shared_ptr<Message> message);
    // 初始化连接
    initConnect();
}

void MessageItem::initUI(std::shared_ptr<Message> message)
{
    // 1. 创建对象和布局管理器
    QGridLayout *layout = new QGridLayout();
    layout->setContentsMargins(30, 10, 40, 0);
    layout->setSpacing(10);
    // 这个 MessageItem 最低不能低于 100
    this->setMinimumHeight(100);
    this->setLayout(layout);

    // 2. 创建头像
    QPushButton *avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(40, 40);
    avatarBtn->setIconSize(QSize(40, 40));
    avatarBtn->setIcon(message->m_sender.m_avatar);
    avatarBtn->setStyleSheet("QPushButton { border: none;}");
    if (m_isLeft)
    {
        layout->addWidget(avatarBtn, 0, 0, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    }
    else
    {
        layout->addWidget(avatarBtn, 0, 1, 2, 1, Qt::AlignTop | Qt::AlignLeft);
    }

    // 3. 创建名字和时间
    QLabel *nameLabel = new QLabel();
    nameLabel->setText(message->m_sender.m_nickName + " | " + message->m_time);
    nameLabel->setAlignment(Qt::AlignBottom);
    nameLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
    if (m_isLeft)
    {
        layout->addWidget(nameLabel, 0, 1);
    }
    else
    {
        layout->addWidget(nameLabel, 0, 0, Qt::AlignRight);
    }

    // 4. 创建消息内容
    QWidget *contentWidget = MessageContentFactory::makeMessageContent(m_isLeft, message);
    if (m_isLeft)
    {
        layout->addWidget(contentWidget, 1, 1);
    }
    else
    {
        layout->addWidget(contentWidget, 1, 0);
    }
}

void MessageItem::initConnect()
{
    // 5. 连接信号槽, 处理用户点击头像的操作
    connect(avatarBtn, &QPushButton::clicked, messageItem, [=]()
            {
        MainWidget* mainWidget = MainWidget::getInstance();
        UserInfoWidget* userInfoWidget = new UserInfoWidget(message.sender, mainWidget);
        userInfoWidget->exec(); });

    // 6. 当用户修改了昵称的时候, 同步修改此处的用户昵称.
    if (!m_isLeft)
    {
        // 只是针对右侧消息(自己的消息) 做下列操作.
        DataCenter *dataCenter = DataCenter::getInstance();
        connect(dataCenter, &DataCenter::changeNicknameDone, this, [=]()
                { nameLabel->setText(dataCenter->getMyself()->nickname + " | " + message.time); });

        connect(dataCenter, &DataCenter::changeAvatarDone, this, [=]()
                {
            UserInfo* myself = dataCenter->getMyself();
            avatarBtn->setIcon(myself->avatar); });
    }
}

TextMessageContent::TextMessageContent(bool isLeft, std::shared_ptr<Message> message)
    : m_isLeft(isLeft)
{
    // 设置 布局策略
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 设置字体
    QFont font;
    font.setFamily(Setting::getInstance()->m_messageContentFontFamily);
    font.setPixelSize(Setting::getInstance()->m_messageContentFontSize);

    // 创建内容标签
    QLabel *contentLabel = new QLabel(this);
    contentLabel->setText(message->m_content);
    contentLabel->setFont(font);
    contentLabel->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    contentLabel->setWordWrap(true); // 设置文本自动换行
    contentLabel->setStyleSheet("QLabel { padding: 0 10px; line-height: 1.2; background-color: transparent; }");
}

void TextMessageContent::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    // 1. 获取到父元素的宽度
    QObject *object = this->parent();
    if (!object->isWidgetType())
    {
        // 当前这个对象的父元素不是预期的 QWidget, 此时不需要进行任何后续的绘制操作.
        return;
    }
    QWidget *parent = dynamic_cast<QWidget *>(object);
    int width = parent->width() * 0.6;

    // 2. 计算当前文本, 如果是一行放置, 需要多宽.
    QFontMetrics metrics(this->label->font());
    int totalWidth = metrics.horizontalAdvance(this->label->text());

    // 3. 计算出此处的行数是多少 (40 表示左右各有 20px 的边距)
    int rows = (totalWidth / (width - 40)) + 1;
    if (rows == 1)
    {
        // 如果此时得到的行数就只有一行
        width = totalWidth + 40;
    }

    // 4. 根据行数, 计算得到高度. (20 表示上下各有 10px 的边距)
    int height = rows * (this->label->font().pixelSize() * 1.2) + 20;

    // 5. 绘制圆角矩形和箭头
    QPainter painter(this);
    QPainterPath path;
    // 设置 "抗锯齿"
    painter.setRenderHint(QPainter::Antialiasing);
    if (m_isLeft)
    {
        painter.setPen(QPen(QColor(255, 255, 255)));
        painter.setBrush(QColor(255, 255, 255));

        // 绘制圆角矩形
        painter.drawRoundedRect(10, 0, width, height, 10, 10);
        // 绘制箭头
        path.moveTo(10, 15);
        path.lineTo(0, 20);
        path.lineTo(10, 25);
        path.closeSubpath();    // 绘制的线形成闭合的多边形, 才能进行使用 Brush 填充颜色.
        painter.drawPath(path); // 不要忘记真正的绘制操作

        this->label->setGeometry(10, 0, width, height);
    }
    else
    {
        painter.setPen(QPen(QColor(137, 217, 97)));
        painter.setBrush(QColor(137, 217, 97));

        // 圆角矩形左侧边的横坐标位置
        int leftPos = this->width() - width - 10; // 10 是用来容纳 箭头 的宽度
        // 圆角矩形右侧边的横坐标位置
        int rightPos = this->width() - 10;
        // 绘制圆角矩形
        painter.drawRoundedRect(leftPos, 0, width, height, 10, 10);
        // 绘制箭头
        path.moveTo(rightPos, 15);
        path.lineTo(rightPos + 10, 20);
        path.lineTo(rightPos, 25);
        path.closeSubpath();
        painter.drawPath(path);

        this->label->setGeometry(leftPos, 0, width, height);
    }

    // 6. 重新设置父元素的高度, 确保父元素足够高, 能够容纳下上述绘制的消息显示的区域
    //    注意高度要涵盖之前名字和时间的 label 的高度, 以及留点冗余空间.
    parent->setFixedHeight(height + 50);
}

ImageMessageContent::ImageMessageContent(bool isLeft, std::shared_ptr<Message> message)
    : m_isLeft(isLeft)
{
}

FileMessageContent::FileMessageContent(bool isLeft, std::shared_ptr<Message> message)
    : m_isLeft(isLeft)
{
    QLabel *fileNameLabel = new QLabel(this);
    QLabel *fileSizeLabel = new QLabel(this);
    QLabel *isSendLabel = new QLabel(this);
    QPushButton *downloadBtn = new QPushButton(this);


    // 设计样式
    // 文件名称标签的样式设置为纯黑色，字体大小为18px
    fileNameLabel->setStyleSheet("QLabel { font-size: 18px; color: rgb(0, 0, 0); }");
    // 发送和文件大小标签的样式设置为灰色，字体大小为12px
    isSendLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");
    fileSizeLabel->setStyleSheet("QLabel { font-size: 12px; color: rgb(178, 178, 178); }");

    // 下载按钮的样式设置为无边框，背景透明
    downloadBtn->setFixedSize(30, 30);
    downloadBtn->setStyleSheet("QPushButton { border: none; background-image: url(:/images/download.png); }\
                                QPushButton::pressed { background-image: url(:/images/download_pressed.png); }");
    downloadBtn->setIconSize(QSize(20, 20));

    fileNameLabel->setText(message->m_fileName);
    if (message->m_fileSize.isEmpty())
    {
        fileSizeLabel->setText("未知大小");
    }
    else
    {
        if (message->m_fileSize.size() > 6)
        {
            fileSizeLabel->setText(QString::number(message->m_fileSize.toLongLong() / 1024 / 1024) + "MB");
        }
        else if (message->m_fileSize.size() > 3)
        {
            fileSizeLabel->setText(QString::number(message->m_fileSize.toLongLong() / 1024) + "KB");
        }
        else
        {
            fileSizeLabel->setText(message->m_fileSize + "B");
        }
        fileSizeLabel->setAlignment(Qt::AlignVCenter | Qt::AlignRight);
    }
    else
    {
        isSendLabel->setText("等待接收");
    }

    // 设计提示词
    if (m_isLeft)
    {
        isSendLabel->setText("已发送"); // 这里需要根据服务器的反馈来决定提示词
    }
    else
    {
        isSendLabel->setText("已下载"); // 这里需要根据服务器的反馈来决定提示词
    }

    // 设置布局
    QGridLayout *gridLayout = new QGridLayout();
    gridLayout->addWidget(fileNameLabel, 0, 0, 1, 2);
    gridLayout->addWidget(fileSizeLabel, 2, 0, 1, 1);
    gridLayout->addWidget(isSendLabel, 2, 1, 1, 1);

    this->setLayout(gridLayout);
}

QWidget *MessageContentFactory::makeMessageContent(bool isLeft, std::shared_ptr<Message> message)
{
    switch (message->m_messageType)
    {
    case MessageType::TextType:
        return new TextMessageContent(isLeft, message);
    case MessageType::ImageType:
        return new ImageMessageContent(isLeft, message);
    case MessageType::FileType:
        return new FileMessageContent(isLeft, message);
    default:
        return nullptr;
    }
}
